;
(function($, $$) {

    $.fn.tree = function(options) {
        var self = this, args = Array.prototype.slice.call(arguments);
        args.push($$.Tree);
        var result = $$.createWidgetByJQuery.apply(self, args);
        if (result.jqObj !== undefined && options !== "widget") {
            return self;
        }
        return result;
    };

    $$.Tree = function(self, options) {
        if (!(this instanceof $$.Tree)) {
            return new $$.Tree(self, options);
        }
        var defaults = {
            url : null,
            checkButton : false,
            getMoreData : null,
            hoverClass : "uiItemHover",
            selectedClass : "uiItemSelected",
            line1Class : "uiLine1",
            line2Class : "uiLine2",
            line3Class : "uiLine3",
            plusClass : "uiPlus",
            minusClass : "uiMinus",
            insertClass : "uiItemInsert",
            draggable : false,
            beforeOpen : null,
            open : null,
            beforeClose : null,
            close : null,
            animateTime : $$.defaultAnimateDuration,

            error : null,
            select : null,


            itemHeight : 0,
            treeJSON : null,
            insertTipHTML : '<span class="uiInsertTip"></span>',
            treeItemHTML : '<li class="uiTreeItem"></li>',
            itemHTML : '<span class="uiItem"></span>',
            iconHTML : '<span class="uiTreeIcon"></span>',
            nameHTML : '<span class="uiName"></span>'
        };
        var opts = $.extend(defaults, options);
        $$.Tree.prototype.superClass.call(this, self, opts);
        this.init();
    }
    $$.inherit($$.Tree, $$.Widget, {
        init : function() {
            var treeObj = this;
            treeObj.createWidget();
            initTree(treeObj.jqObj, treeObj.opts);
            return treeObj;
        }
    });

    function initTree(self, opts) {
        if (opts.url === null) {
            return;
        }
        self.addClass("uiTree uiWidget ");
        $.ajax({
            url : opts.url,
            dataType : "json",
            success : function(data) {
                opts.treeJSON = data;
                setTree(self, opts, self, [], true);
                opts.itemHeight = self.find(">ul>.uiTreeItem").outerHeight(true);
                initEvent(self, opts);
            },
            error : function() {
                if ($.isFunction(opts.error)) {
                    opts.error();
                }
            }
        });
        return self;
    }

    function initEvent(self, opts) {
        self.bind("click.uiTree", function(e) {
            var target = $(e.target), treeItem;
            if (target.hasClass(opts.plusClass)) {
                var parentObj = target.parent(".uiTreeItem");
                if ($.isFunction(opts.beforeOpen)) {
                    if (opts.beforeOpen.call(self[0], parentObj, e) === false) {
                        return;
                    }
                }
                target.removeClass(opts.plusClass).addClass(opts.minusClass);
                var success = true;
                treeItem = parentObj;
                treeItem.css("height", opts.itemHeight);
                if (parentObj.find(">ul>.uiTreeItem").length === 0) {
                    var indexArr = getIndexArrayByTreeItem(parentObj);
                    success = setTree(self, opts, treeItem, indexArr, true);
                }
                if (success) {
                    toggleTreeItem(treeItem, opts);
                }
                if ($.isFunction(opts.open)) {
                    opts.open.call(self[0], parentObj, e)
                }
            }
            else
            if (target.hasClass(opts.minusClass)) {
                var parentObj = target.parent(".uiTreeItem");
                if ($.isFunction(opts.beforeClose)) {
                    if (opts.beforeClose.call(self[0], parentObj, e) === false) {
                        return;
                    }
                }
                target.removeClass(opts.minusClass).addClass(opts.plusClass);
                treeItem = parentObj
                toggleTreeItem(treeItem, opts);
                if ($.isFunction(opts.close)) {
                    opts.close.call(self[0], parentObj, e)
                }
            }
            else
            if (target.hasClass("uiUnChecked") || target.hasClass("uiChildrenChecked")) {
                var parentObj = target.parent();
                changeCheckStatus(parentObj, true);

            }
            else
            if (target.hasClass("uiChecked")) {
                var parentObj = target.parent();
                changeCheckStatus(parentObj, false);

            }
            else
            if (target.parent(".uiItem").length !== 0) {
                var obj = target.parent(".uiItem");
                if ($.isFunction(opts.select)) {
                    if (opts.select.call(self[0], obj.parent(".uiTreeItem"), e) === false) {
                        return;
                    }
                }
                self.find("." + opts.selectedClass).removeClass(opts.selectedClass);
                obj.addClass(opts.selectedClass);
            }
        })
            .bind("mouseover.uiTree mouseout.uiTree", function(e) {
                var target = $(e.target).parent(".uiItem");
                if (target.length !== 0) {
                    target.toggleClass(opts.hoverClass);
                }
            });

        if (opts.draggable) {
            var visibleItemList = null;
            self.draggable({
                getUserMask : function() {
                    var selectedObj = self.find("." + opts.hoverClass);
                    if (selectedObj.length !== 0) {
                        visibleItemList = self.find(".uiItem:visible");
                        originOffset = selectedObj.offset();
                        return selectedObj.clone().removeClass(opts.selectedClass).unbind().css({position : "absolute", left : originOffset.left, top : originOffset.top, "z-index" : 99}).insertAfter(selectedObj);
                    }
                    return selectedObj;
                },
                event : {
                    doing : function(mask, offset) {
                        checkArea(self, visibleItemList, opts, mask, offset);
                    },
                    stop : function(mask, offset) {
                        destObj = checkArea(self, visibleItemList, opts, mask, offset);
                        visibleItemList = null;
                        if (destObj.length === 0) {
                            return;
                        }
                        var insertTip = destObj.removeClass(opts.insertClass).children(".uiInsertTip");
                        var insertFunc = "insertAfter";
                        if (insertTip.hasClass("uiInsertBefore")) {
                            insertFunc = "insertBefore";
                        }
                        insertTip.remove();
                        destObj = destObj.parent(".uiTreeItem");
                        var moveObj = mask.parent(".uiTreeItem");
                        if (moveObj[0] !== destObj[0]) {
                            var changeDestIcon = false;
                            var changeInsertIcon = false;
                            var removeObj = removeTreeItem(moveObj, opts);
                            addTreeItem(destObj, removeObj.treeItem, removeObj.data, insertFunc, opts);
                        }
                    }
                }
            });
        }
    }

    function setTree(self, opts, dest, indexArr, getData, hide) {
        var json = opts.treeJSON;
        var noData = false;
        var allSpaceFlag = false;

        var line1HTML = '<span class="uiTreeIcon ' + opts.line1Class + '"></span>';
        var spaceHTML = '<span class="uiTreeIcon uiSpace"></span>';

        var paddingItemHTML = "";
        if ($.isArray(indexArr)) {
            $.each(indexArr, function(index, data) {
                if (data === json.length - 1) {
                    paddingItemHTML += spaceHTML;
                }
                else {
                    paddingItemHTML += line1HTML;
                }
                json = json[data];
                if (json["ajax"] === true) {
                    noData = true;
                    return false;
                }
                else {
                    json = json["children"];
                }
            });
        }
        if (noData) {
            if ($.isFunction(opts.getMoreData) && getData) {
                opts.getMoreData(indexArr, function(data) {
                    json["ajax"] = false;
                    json["children"] = data;
                    if (setTree(self, opts, dest, indexArr, false)) {
                        toggleTreeItem(dest, opts);
                    }
                });
            }
            return false;
        }
        var icon = $(opts.iconHTML);
        var totalItem = json.length;
        var checkBoxClass = "uiUnChecked";
        if (dest.children(".uiChecked").length !== 0) {
            checkBoxClass = "uiChecked";
        }
        var itemList = $("<ul></ul>");
        if (hide === true) {
            itemList.hide();
        }
        $.each(json, function(index, data) {
            var item = $(opts.treeItemHTML);
            if (paddingItemHTML !== "") {
                item.append($(paddingItemHTML))
            }
            var itemClass = opts.line3Class;
            if (index === totalItem - 1) {
                itemClass = opts.line2Class;
            }
            if ("ajax" in data || "children" in data) {
                itemClass = opts.plusClass;
            }
            item.append(icon.clone().addClass(itemClass));
            if (opts.checkButton) {
                item.append(icon.clone().addClass(checkBoxClass));
            }
            item.append($(opts.itemHTML).append(icon.clone().addClass(data.type)).append($(opts.nameHTML).html(data.name)));
            if (itemClass === opts.plusClass) {
                var tmpIndex = indexArr.slice(0);
                tmpIndex.push(index);
                setTree(self, opts, item, tmpIndex, false, true);
            }
            itemList.append(item);
        });
        dest.append(itemList);
        return true;
    }

    function checkArea(self, visibleItemList, opts, mask, offset) {
        self.find("." + opts.insertClass).removeClass(opts.insertClass).children(".uiInsertTip").remove();
        var index = Math.ceil((offset.top - self.offset().top + parseInt(self.scrollTop())) / opts.itemHeight);
        var destObj = visibleItemList.eq(index - 1);
        var destOffset = destObj.offset();
        var destLeft = destOffset.left;
        var destTop = destOffset.top;
        var destRight = destLeft + destObj.outerWidth();
        var destBottom = destTop + destObj.outerHeight();
        var maskLeft = offset.left;
        var maskTop = offset.top;
        var maskRigth = maskLeft + mask.outerWidth();
        var maskBottom = maskTop + mask.outerHeight();

        var moveObj = mask.parent(".uiTreeItem");
        var checkObj = destObj.parent(".uiTreeItem");
        if (checkObj[0] === moveObj[0]) {
            return $();
        }
        var inserIndexArr = getIndexArrayByTreeItem(moveObj);
        var destIndexArr = getIndexArrayByTreeItem(checkObj);
        var isChild = false;
        if (inserIndexArr.length < destIndexArr.length) {
            isChild = true;
            for (var i = 0, len = inserIndexArr.length; i < len; i++) {
                if (inserIndexArr[i] != destIndexArr[i]) {
                    isChild = false;
                }
            }
        }
        if (isChild) {
            return $();
        }
        if (!(destLeft > maskRigth | destTop > maskBottom | destRight < maskLeft | destBottom < maskTop)) {
            var insertClass = "uiInsertBefore";
            $("#test").html(destTop - maskTop);
            if ((Math.abs(destTop - maskTop) % opts.itemHeight) > (opts.itemHeight / 2)) {
                insertClass = "uiInsertAfter";
            }
            return destObj.addClass(opts.insertClass).prepend($(opts.insertTipHTML).addClass(insertClass));
        }
        return $();
    }

    function toggleTreeItem(treeItem, opts) {
        var treeItemHeight = opts.itemHeight;
        var callBackFunc = "close";
        var showFlag = treeItem.height() == opts.itemHeight ? true : false;
        if (showFlag) {
            var treeItemClone = treeItem.clone().height("auto").find(">ul").show().end().css($$.cssShow).insertBefore(treeItem);
            treeItemHeight = treeItemClone.height();
            treeItemClone.remove();
            treeItem.find(">ul").show();
            callBackFunc = "open";
        }
        treeItem.animate({"height" : treeItemHeight}, opts.animateTime, function() {
            if (!showFlag) {
                $(this).find(">ul").hide();
            }
            $.style(this, "height", "");
            if ($.isFunction(opts[callBackFunc])) {
                opts[callBackFunc].call(self);
            }
        });
    }

    function getIndexArrayByTreeItem(obj) {
        var indexArr = [];
        if (obj.hasClass("uiTreeItem")) {
            while (obj.length !== 0 && !obj.hasClass("uiTree")) {
                indexArr.push(obj.prevAll(".uiTreeItem").length);
                obj = obj.parent("ul").parent(".uiTreeItem");
            }
        }
        return indexArr.reverse();
    }

    function getTreeItemByIndexArray(arr, treeObj) {
        var obj = treeObj;
        if ($.isArray(arr)) {
            for (var i = 0, len = arr.length; i < len; i++) {
                obj = obj.find(">ul >.uiTreeItem").eq(arr[i]);
                if (obj.length === 0) {
                    break;
                }
            }
        }
        else {
            obj = $();
        }
        return obj;
    }

    function changeItemIcon(obj, cloneIcon, index) {
        obj.find(">ul>.uiTreeItem").each(function() {
            var destObj = $(this);
            var iconList = destObj.children(".uiTreeIcon");
            var Iconfilter = ":lt(" + index + ")";
            iconList.filter(Iconfilter).remove();
            destObj.prepend(cloneIcon.clone());
            changeItemIcon(destObj, cloneIcon, index);
        });
    }

    function removeTreeItem(obj, opts) {
        var removeIndexArr = getIndexArrayByTreeItem(obj);
        var removeJSON = opts.treeJSON;
        for (var i = 0, len = removeIndexArr.length - 1; i < len; i++) {
            removeJSON = removeJSON[removeIndexArr[i]].children;
        }
        var removeIndex = removeIndexArr.pop();
        var removeData = removeJSON[removeIndex];
        removeJSON.splice(removeIndex, 1);

        var iconList;
        var plusMinusFilter = "." + opts.plusClass + ", ." + opts.minusClass;
        var Iconfilter;
        var iconOffsetIndex = -1;
        if (opts.checkButton) {
            iconOffsetIndex = -2;
        }
        if (obj.next(".uiTreeItem").length === 0) {
            iconList = obj.prev(".uiTreeItem").children(".uiTreeIcon");
            if (iconList.filter(plusMinusFilter).length === 0) {
                iconList.eq(iconOffsetIndex).removeClass(opts.line3Class).addClass(opts.line2Class);
            }
            iconList = obj.children(".uiTreeIcon");
            if (iconList.filter(plusMinusFilter).length === 0) {
                iconList.eq(iconOffsetIndex).removeClass(opts.line2Class).addClass(opts.line3Class);
            }
        }
        var returnObj = {
            data : removeData,
            treeItem : obj
        }
        var parentObj = obj.parent("ul").parent(".uiTreeItem");
        if (opts.checkButton) {
            var checkObj = obj.next(".uiTreeItem");
            var arguments = [];
            if (checkObj.length === 0) {
                checkObj = obj.prev(".uiTreeItem");
            }
            if (checkObj.length === 0) {
                checkObj = parentObj;
                arguments.push(false);
            }
            obj.remove();
            arguments.unshift(checkObj);
            changeCheckStatus.apply(null, arguments);
        }
        else {
            obj.remove();
        }
        var praentIconObj = parentObj.find("." + opts.plusClass + ", ." + opts.minusClass);
        if (praentIconObj.length !== 0) {
            if (parentObj.find(".uiTreeItem").length === 0) {
                praentIconObj.removeClass(opts.plusClass + " " + opts.minusClass);

                if (parentObj.next(".uiTreeItem").length === 0) {
                    praentIconObj.addClass(opts.line2Class);
                }
                else {
                    praentIconObj.addClass(opts.line3Class);
                }
            }
        }
        return returnObj;
    }

    function addTreeItem(destObj, addObj, addData, insertFunc, opts) {
        var changeDestIcon = false;
        var changeInsertIcon = false;
        var destIndexArr = getIndexArrayByTreeItem(destObj);
        var destJSON = opts.treeJSON;
        for (var i = 0, len = destIndexArr.length - 1; i < len; i++) {
            destJSON = destJSON[destIndexArr[i]].children;
        }
        var destIndex = destIndexArr.pop();

        if (insertFunc === "insertAfter") {
            if (destObj.next(".uiTreeItem").length === 0) {
                changeDestIcon = true;
            }
            destIndex++;
        }
        destJSON.splice(destIndex, 0, addData);
        var iconList;
        var plusMinusFilter = "." + opts.plusClass + ", ." + opts.minusClass;
        var Iconfilter;
        var iconOffsetIndex = -1;
        if (opts.checkButton) {
            iconOffsetIndex = -2;
        }

        iconList = destObj.children(".uiTreeIcon");
        var destObjIconListLen = iconList.length;
        Iconfilter = ":lt(" + (destObjIconListLen + iconOffsetIndex) + ")";
        var cloneIcon = iconList.filter(Iconfilter).clone();
        iconList = addObj.children(".uiTreeIcon");
        var addObjIconListLen = iconList.length;
        Iconfilter = ":lt(" + (addObjIconListLen + iconOffsetIndex) + ")";
        iconList.filter(Iconfilter).remove();
        addObj.prepend(cloneIcon)[insertFunc](destObj);
        var addObjChildren = addObj.find(">ul>.uiTreeItem");
        if (addObjChildren.length !== 0) {
            var cloneIconClass = opts.line1Class;
            if (changeDestIcon) {
                cloneIconClass = "uiSpace";
            }
            cloneIcon = cloneIcon.clone().add($(opts.iconHTML).addClass(cloneIconClass));
            changeItemIcon(addObj, cloneIcon, addObjIconListLen + iconOffsetIndex + 1);
        }
        if (changeDestIcon) {
            iconList = destObj.children(".uiTreeIcon");
            if (iconList.filter(plusMinusFilter).length === 0) {
                iconList.eq(iconOffsetIndex).removeClass(opts.line2Class).addClass(opts.line3Class);
            }
            iconList = addObj.children(".uiTreeIcon");
            if (iconList.filter(plusMinusFilter).length === 0) {
                iconList.eq(iconOffsetIndex).removeClass(opts.line3Class).addClass(opts.line2Class);
            }
        }
        if (opts.checkButton) {
            changeCheckStatus(addObj);
        }
    }

    function changeCheckStatus(obj, checked) {
        var childrenChenckedClass = "uiChildrenChecked";
        var filterStr = ".uiChecked, .uiChildrenChecked";
        var allClassStr = "uiUnChecked uiChecked uiChildrenChecked";
        var addClassStr = "uiUnChecked";
        var findClassStr = ".uiChecked";
        if (arguments.length === 1) {
            var checked = false;
            if (obj.children(filterStr).length !== 0) {
                checked = true;
            }
        }
        if (checked) {
            filterStr = ".uiUnChecked, .uiChildrenChecked";
            addClassStr = "uiChecked";
            findClassStr = ".uiUnChecked";
        }
        if (arguments.length === 2) {
            obj.find(filterStr).removeClass(allClassStr).addClass(addClassStr);
        }
        obj = obj.parent("ul").parent(".uiTreeItem");
        while (obj.length !== 0) {
            var findObjList = obj.find(findClassStr);
            var changeObj = obj.children(filterStr);
            if (findObjList.length !== 0) {
                changeObj.removeClass(allClassStr).addClass(childrenChenckedClass);
            }
            else {
                changeObj.removeClass(allClassStr).addClass(addClassStr);
            }
            obj = obj.parent("ul").parent(".uiTreeItem");
        }
    }
})(jQuery, BASE);
